#include "CommandMap.h"
#include "ErrorCodes.h"
#include <stdio.h>
#include <malloc.h>
#include <string.h>
char **ParseCommand(char* cmd);
int PrintHelp(char **args);

/*!
  Create a command map
  /param size Size of the hash table. Recommended that size=n
  /return A command map
*/
CommandMap CreateCommandMap(int size)
{
	CommandMap cm;
	cm.Map = CreateHashTable(size);
	CMSet(&cm, PrintHelp, "help", "Print Help");
	return cm;
}

/*!
  Execute a command
  /param map The command map to query
  /param cmd command key
  /return A global error code
*/
int CMExecute(CommandMap *map, char *cmd) {
	int (*func)(char**);
	Command *c;
	char **args;

	args = ParseCommand(cmd);
	c = (Command*)HTGet(&(map->Map), args[0]);
	args[0] = (char*)map;

	if (c == 0x0)
		return EC_NOT_FOUND;

	func = (int (*)(char**))c->Function;
	func(args);
	free(args);
	

	return EC_SUCCESS;
}

/*!
  Map a string to a function
  /param map The command map to modify
  /param func A function pointer. Return Type: int, Arguments: char**
  /param cmd Key string
  /param description Command description for 'help'
  /return A global error code
*/
int CMSet(CommandMap *map, int (*func)(char**), char *cmd, char *description) {
	Command *c = (Command*)malloc(sizeof(Command));
	c->Function = (ADDRESS)func;
	c->Description = description;
	HTSet(&(map->Map), cmd, c);

	return EC_SUCCESS;
}

/*!
  Separate a string using spaces as delimiters
  /param cmd The string to parse
  /return An array of strings
*/
char **ParseCommand(char* cmd)
{
	char **R;
	int i;
	int len=strlen(cmd)-1;
	int count=0;
	for (i=0; i<len; i++)
	{
		if (cmd[i] == ' ') {
			cmd[i] = '\0';
			count=count+1;
		}
	}
	R = (char**)malloc(sizeof(ADDRESS)*(count+1));
	R[0] = &cmd[0];
	count=1;
	for (i=1; i<len; i++)
	{
		if (cmd[i-1] == '\0') {
			R[count] = &cmd[i];
			count=count+1;
		}
	}
	R[count] = 0x0;
	return R;
}

/*!
  Read a string up to the newline character
  /param line A pointer to the destination byte array
  /param bytes A pointer to the size of the destination byte array
  /param stream The file stream to read from (ie. stdin, stdout, etc.)
*/
int getline(char *line, int *bytes, FILE *stream)
{
	int nbytes=0;
	char ch;
	while ((ch=getc(stream)) != '\n' && nbytes < *bytes-1)
	{
		line[nbytes] = ch;
		nbytes=nbytes+1;
	}
	line[nbytes] = '\0';
	if (nbytes == *bytes-1)
		return -2;
	return nbytes;
}

/*!
  Print help for the mapping
  Mapped function
  /param args An array of string arguments. See ParseCommand
  /return A global error code
*/
int PrintHelp(char **args)
{
	CommandMap *map = (CommandMap*)args[0];
	if (args[1] == 0x0 || strcmp(args[1], "")==0)
	{
		LinkedList keys = HTGetKeys(&(map->Map));
		LinkedListNode *iter = keys.Head;
		while (iter != 0x0)
		{
			printf("%s  --  ", (char*)iter->Value);
			Command *c = HTGet(&(map->Map), (char*)iter->Value);
			printf("%s\n", c->Description);
			iter = iter->Next;
		}
	}
	else {
		printf("<only generic help is available at the moment>\n");
	}
	return EC_SUCCESS;
}
